﻿using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;
using System.Threading.Tasks;
using SDCloudSolution.SDCloud.DataLayer.Model.Interfaces;
using SDCloudSolution.SDCloud.Entities.Models;
using System.IO;
using System.Xml;
using System.Xml.Schema;

namespace SDCloudSolution.SDCloud.DataLayer.Model
{
    public class ModelMetadataDataProvider
    {
        private const string XMILE_XPATH_MODEL_VENDOR = "/x:xmile/x:header/x:vendor";
        private const string XMILE_XPATH_MODEL_NAME = "/x:xmile/x:header/x:name";

        private const string XMILE_XPATH_MODEL_STOCKS = "/x:xmile/x:model/x:variables/x:stock";
        private const string XMILE_XPATH_MODEL_FLOWS = "/x:xmile/x:model/x:variables/x:flow";
        private const string XMILE_XPATH_MODEL_AUXES = "/x:xmile/x:model/x:variables/x:aux";

        private const string XMILE_EQUATION_NODE_NAME = "eqn";

        public static ModelMetadataEntity GetXmileModelMetadata(Stream xmileModelStream)
        {
            ModelMetadataEntity result = new ModelMetadataEntity();

            var settings = new XmlReaderSettings();
            settings.CloseInput = false;
            settings.IgnoreComments = true;

            xmileModelStream.Seek(0, SeekOrigin.Begin);
            using (var reader = XmlReader.Create(xmileModelStream, settings))
            {
                try
                {
                    var document = new XmlDocument();
                    document.Load(reader);

                    XmlNamespaceManager namespaces = new XmlNamespaceManager(document.NameTable);
                    namespaces.AddNamespace("x", @"http://docs.oasis-open.org/xmile/ns/XMILE/v1.0");

                    XmlNode root = document.DocumentElement;

                    /* Getting basic model information */
                    result.Name = getValueByXpath(root, XMILE_XPATH_MODEL_NAME, namespaces);
                    result.Vendor = getValueByXpath(root, XMILE_XPATH_MODEL_VENDOR, namespaces);

                    /* Getting configruable model components */
                    result.ConfigurableStocks = 
                        getXmileModelConfigurables(root, XMILE_XPATH_MODEL_STOCKS, namespaces);
                    result.ConfigurableFlows =
                        getXmileModelConfigurables(root, XMILE_XPATH_MODEL_FLOWS, namespaces);
                    result.ConfigurableAuxes =
                        getXmileModelConfigurables(root, XMILE_XPATH_MODEL_AUXES, namespaces);

                }
                catch (XmlException)
                {
                    /* TODO: handle properly */
                }
            }
            return result;
        }


        private static string getValueByXpath(XmlNode root, string xpath, XmlNamespaceManager nsmrg)
        {
            string result = null;
            XmlNode node = root.SelectSingleNode(xpath, nsmrg);

            if (null != node)
            {
                result = node.InnerText;
            }

            return result;
        }

        private static Dictionary<string, object> getXmileModelConfigurables(XmlNode root, string xpath, XmlNamespaceManager nsmrg)
        {
            Dictionary<string, object> result = new Dictionary<string, object>();

            XmlNodeList nodeList = root.SelectNodes(xpath, nsmrg);

            foreach (XmlNode node in nodeList)
            {
                foreach (XmlNode childNode in node.ChildNodes)
                {
                    if (childNode.Name.Equals(XMILE_EQUATION_NODE_NAME))
                    {
                        long longValue;
                        double doubleValue;

                        if (long.TryParse(childNode.InnerText, out longValue))
                        {
                            result.Add(node.Attributes["name"].Value, longValue);
                        }
                        else if (double.TryParse(childNode.InnerText, out doubleValue))
                        {
                            result.Add(node.Attributes["name"].Value, doubleValue);
                        }
                    }
                }
            }


            return result;
        }
    }
}
